package com.hexinfo.dmpro.monitor.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hexinfo.dmpro.common.base.BaseService;
import com.hexinfo.dmpro.common.base.Page;
import com.hexinfo.dmpro.common.base.PageResult;
import com.hexinfo.dmpro.monitor.dao.CmStateDao;
import com.hexinfo.dmpro.monitor.model.base.MonitorReq;
import com.hexinfo.dmpro.monitor.model.cm.*;
import com.hexinfo.dmpro.monitor.service.serviceparam.CmTargetParamService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author peng
 * @date 2022/2/28 14:32
 * 获取服务  角色状态
 * 只采集异常服务信息
 */
@Service
@Slf4j
public class CmStateService extends BaseService {

    @Autowired
    private ClusterHostRoleService clusterHostRoleService;
    @Autowired
    private ClusteAllRolesService clusteAllRolesService;
    @Autowired
    private CmStateDao cmStateDao;
    @Autowired
    private CmTargetParamService cmTargetParamService;

    @Value("${warn.cmServiceWarn}")
    private String cmServiceWarn;
    private String apiUrl = "query=select health_unknown_rate * 100 as \"UNKNOWN\",health_disabled_rate * 100 as \"DISABLED\"," +
            "health_bad_rate * 100 as \"BAD\",health_concerning_rate * 100 as \"CONCERNING\",health_good_rate * 100 as \"GOOD\" " +
            "where entityName=\"{service}\"&from={fromTime}&to={toTime}";

    public void getSate(MonitorReq monitorReq, boolean flag) {
        //获取ISO 8601格式的UTC（协调世界时）
        DateTime dateTime = DateUtil.offsetHour(DateUtil.date(), -8);
        String toTime = DateUtil.format(dateTime, "yyyy-MM-dd'T'HH:mm'Z'");
        String fromTime = DateUtil.format(DateUtil.offsetMinute(dateTime, -5), "yyyy-MM-dd'T'HH:mm'Z'");
        Map<String, Object> serviceMap = new HashMap<>();
        List<Map<String, String>> serviceList = new ArrayList<>();
        List<Map<String, String>> serviceListNow = new ArrayList<>();
        String warnAlert = "";
        JSONArray jsonArray = clusteAllRolesService.getAllRolesInfo(monitorReq, flag);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject serviceJSON = jsonArray.getJSONObject(i);
            //健康的服务不存入
            Map<String, String> map = new HashMap<>();
            //获取5分钟内状态级别最高的状态
            String sqlData = apiUrl.replace("{service}",serviceJSON.getString("name"))
                    .replace("{fromTime}",fromTime)
                    .replace("{toTime}",toTime);
            String state = servicesHistoryState(sqlData, monitorReq);
            if (StrUtil.isNotBlank(state)){
                map.put("healthSummary", state);
            }else {
                map.put("healthSummary", serviceJSON.getString("healthSummary"));
            }
            map.put("displayName", serviceJSON.getString("name"));
            map.put("type", serviceJSON.getString("type").toLowerCase());
            map.put("serviceState", serviceJSON.getString("serviceState"));
            //添加运行状况测试
            String healthChecks = servicesHealthChecks(serviceJSON.getString("name"), monitorReq);
            map.put("healthChecks", healthChecks);
            map.put("name", serviceJSON.getString("name"));
            if (serviceJSON.getString("healthSummary").equals("BAD") || serviceJSON.getString("healthSummary").equals("CONCERNING")) {
                serviceList.add(map);
            }
            serviceListNow.add(map);
        }
        serviceMap.put("req", monitorReq);
        if (serviceList != null && serviceList.size() > 0) {
            serviceMap.put("list", serviceList);
            cmStateDao.insertService(serviceMap);
        }
        //最新时刻数据 处理查询效率问题
//        serviceMap.remove("list");
        serviceMap.put("list", serviceListNow);
        cmStateDao.deleteServiceNow(serviceMap);
        cmStateDao.insertServiceNow(serviceMap);

        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject serviceJSON = jsonArray.getJSONObject(i);
            String serviceType = serviceJSON.getString("name");
            monitorReq.setMonitorType(serviceType);
            String state = "GOOD";
            Map<String, Object> roleMap = new HashMap<>();
            List<Map<String, String>> roleList = new ArrayList<>();

            JSONArray hostRoleInfos = clusterHostRoleService.getHostRoleInfo(monitorReq, flag);
            for (int j = 0; j < hostRoleInfos.size(); j++) {
                JSONObject roleJSON = hostRoleInfos.getJSONObject(j);
                //只存入异常的信息
                if (roleJSON.getString("healthSummary").equals("BAD") || roleJSON.getString("healthSummary").equals("CONCERNING")) {
                    Map<String, String> map = new HashMap<>();
                    map.put("hostname", roleJSON.getJSONObject("hostRef").getString("hostname"));
                    map.put("serviceType", serviceType);
                    map.put("roleType", roleJSON.getString("type"));
                    map.put("roleState", roleJSON.getString("roleState"));
                    map.put("healthSummary", roleJSON.getString("healthSummary"));
                    map.put("healthChecks", roleJSON.getString("healthChecks"));
                    roleList.add(map);
                    if (!state.equals("BAD")){
                        state = roleJSON.getString("healthSummary");
                    }
                }
            }
            roleMap.put("req", monitorReq);
            roleMap.put("list", roleList);
            if (roleList.size() > 0) {
                if (state.equals("BAD")){
                    warnAlert = warnAlert + serviceType + " 服务状态: 异常"+"\n";
                }
                cmStateDao.insertRole(roleMap);
            }
        }

        //发送告警
        try {
            if (StrUtil.isNotBlank(warnAlert)) {
                String warnStr = "CM服务监控：\n" + "【" + monitorReq.getCmName() + "】" + "\n" + warnAlert;
                //发送日常巡检，钉钉
                cmTargetParamService.warnWxDingDingAndLog(monitorReq.getCmFlag(), monitorReq.getCmName(), monitorReq.getClusterFlag(), monitorReq.getClusterName(), "集群服务", warnStr, cmServiceWarn);
            }
        }catch (Exception e){
            log.error("服务状态监控发送告警异常："+e);
        }
    }

    public List<Map<String, String>> selServiceState(MonitorReq monitorReq) {
        //获取ISO 8601格式的UTC（协调世界时）
        DateTime dateTime = DateUtil.offsetHour(DateUtil.date(), -8);
        String toTime = DateUtil.format(dateTime, "yyyy-MM-dd'T'HH:mm'Z'");
        String fromTime = DateUtil.format(DateUtil.offsetMinute(dateTime, -5), "yyyy-MM-dd'T'HH:mm'Z'");
        List<Map<String, String>> serviceListNow = new ArrayList<>();
        JSONArray jsonArray = clusteAllRolesService.getAllRolesInfo(monitorReq, true);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject serviceJSON = jsonArray.getJSONObject(i);
            //健康的服务不存入
            Map<String, String> map = new HashMap<>();
            //获取5分钟内状态级别最高的状态
            String sqlData = apiUrl.replace("{service}",serviceJSON.getString("name"))
                    .replace("{fromTime}",fromTime)
                    .replace("{toTime}",toTime);
            String state = servicesHistoryState(sqlData, monitorReq);
            if (StrUtil.isNotBlank(state)){
                map.put("healthSummary", state);
            }else {
                map.put("healthSummary", serviceJSON.getString("healthSummary"));
            }
            map.put("name", serviceJSON.getString("name"));
            serviceListNow.add(map);
        }
        return serviceListNow;
    }

    /**
     * 获取服务运行状况测试情况
     */
    public String servicesHealthChecks(String service,MonitorReq monitorReq) {
        JSONObject serviceJSON = clusteAllRolesService.getRequestCmApi(monitorReq,service);
        String healthChecks = serviceJSON.getString("healthChecks");
        return healthChecks;
    }

    /**
     * 获取服务历史状态数据
     */
    public String servicesHistoryState(String urlData,MonitorReq monitorReq) {
        JSONObject jsonObject = JSONObject.parseObject(monitorReq.getOtherParam());
        String url = jsonObject.get("cmApi").toString()+"/timeseries?"+urlData;
        String username = jsonObject.get("user").toString();
        String password = jsonObject.get("password").toString();
        JSONObject obj = getRequestCmApi(url,username,password);
        JSONArray requestCmApi = obj.getJSONArray("items");
        for (int i = 0; i < requestCmApi.size(); i++) {
            JSONObject serviceJSON = requestCmApi.getJSONObject(i);
            JSONArray jsonArray = serviceJSON.getJSONArray("timeSeries");
            for (int j = 0; j < jsonArray.size(); j++) {
                JSONObject jsonObject1 = jsonArray.getJSONObject(j);
                JSONArray data = jsonObject1.getJSONArray("data");
                for (int l = 0; l < data.size(); l++) {
                    JSONObject jsonObject2 = data.getJSONObject(l);
                    String value = jsonObject2.getString("value");
                    System.out.println(value);
                    if (!"0.0".equals(jsonObject2.getString("value"))){
                        JSONObject metadata = jsonObject1.getJSONObject("metadata");
                        return metadata.getString("alias");
                    }
                }
            }
        }
        return "";
    }

    public JSONObject getRequestCmApi(String url,String username,String password) {
        String authHeader = "";
        try {
            // 构建Basic Auth认证的Header
            authHeader = StrUtil.format("Basic {}", StrUtil.str(Base64.getEncoder().encodeToString((username + ":" + password).getBytes("utf-8"))));
        }catch (Exception e) {
            log.error("设置Authorization异常", e);
        }
        // 发送GET请求并添加认证信息到Header
        HttpResponse response = HttpRequest.get(url)
                .header("Authorization", authHeader)
                .header("Content-Type", "application/json")
                .execute();
        // 输出响应结果
        JSONObject obj = null;
        if (200 == response.getStatus()){
            String body = response.body();
            obj = JSONObject.parseObject(body);
        }
        return obj;
    }

    /**
     * 首页 查询 集群状态信息
     *
     * @return
     */
    public List<ClusterStateInfo> queryClusterState(StateBaseReqModel model) {
        List<Map<String, String>> createTimeList = cmStateDao.queryCreateTime();
        List<ClusterStateInfo> clusterStateInfos = cmStateDao.queryClusterState(model);

        //某些集群未查到数据时特殊处理
        List<ClusterStateInfo> clusterStateInfosAll = cmStateDao.queryAllCluster();
        if (clusterStateInfos != null && clusterStateInfos.size() > 0) {
            Map<String, ClusterStateInfo> clusterMap = new HashMap<>();
            clusterStateInfos.forEach(cluster -> {
                clusterMap.put(cluster.getCmFlag() + cluster.getClusterFlag(), cluster);
            });
            for (ClusterStateInfo clusterStateInfo : clusterStateInfosAll) {
                if (clusterMap.get(clusterStateInfo.getCmFlag() + clusterStateInfo.getClusterFlag()) == null) {
                    clusterStateInfos.add(clusterStateInfo);
                }
            }
        } else {
            clusterStateInfos = clusterStateInfosAll;
        }

        clusterStateInfos.forEach(base -> {
            Map<String, StateCountInfo> timeMap = new HashMap<>();
            List<StateCountInfo> timeList = new ArrayList<>();
            List<StateCountInfo> stateCountInfoList = base.getStateCountInfoList();
            stateCountInfoList.forEach(stateInfo -> {
                timeMap.put(stateInfo.getCt(), stateInfo);
            });
            createTimeList.forEach(item -> {
                String createTime = item.get("createTime");
                StateCountInfo info = null;
                if (timeMap.get(createTime) != null) {
                    info = timeMap.get(createTime);
                } else {
                    info = new StateCountInfo();
                    info.setCt(createTime);
                    info.setBad(0);
                    info.setConc(0);
                    info.setGood(0);
                }
                timeList.add(info);
            });
            base.setStateCountInfoList(timeList);
        });
        return clusterStateInfos;
    }

    /**
     * 状态页 查询 表格   所有服务异常次数  （实时）
     *
     * @return
     */
    public List<ServiceCountInfo> queryServiceRealTime(StateBaseReqModel model) {
        List<ServiceCountInfo> serviceCountInfos = cmStateDao.queryServiceRealTime(model);
        Map<String, ServiceCountInfo> map = new HashMap<>();
        if (serviceCountInfos != null && serviceCountInfos.size() > 0) {
            serviceCountInfos.forEach(item -> {
                map.put(item.getType(), item);
            });
        }

        //把不符合条件的type的填0补充
        List<ServiceCountInfo> allServiceList = cmStateDao.queryServiceNullCount(model);
        if (allServiceList != null && allServiceList.size() > 0) {
            allServiceList.forEach(allItem -> {
                String type = allItem.getType();
                String name = allItem.getName();
                if (map.get(type) == null) {
                    ServiceCountInfo serviceCountInfo = new ServiceCountInfo();
                    serviceCountInfo.setType(type);
                    serviceCountInfo.setName(name);
                    serviceCountInfo.setBad(0);
                    serviceCountInfo.setConc(0);
                    serviceCountInfo.setGood(0);
                    serviceCountInfos.add(serviceCountInfo);
                }
            });
        }
        return serviceCountInfos;
    }

    /**
     * 状态页 查询 服务状态信息
     *
     * @return
     */
    public List<ServiceStateInfo> queryServiceState(StateBaseReqTimeModel model) {
        //获取日期集合
        List<Map<String, String>> createTimeList = queryCreateTimeRange(model);
        List<ServiceStateInfo> serviceStateInfos = cmStateDao.queryServiceState(model);
        int concerningCount = 0;
        int badCount = 0;
        int goodCount = 0;
        // GOOD 健康 CONCERNING 警告  BAD 严重
        if (serviceStateInfos != null && serviceStateInfos.size() > 0) {
            for (ServiceStateInfo serviceStateInfo : serviceStateInfos) {
                List<StateCheckInfo> stateCheckInfoList = serviceStateInfo.getStateCountInfoList();
                if (stateCheckInfoList != null && stateCheckInfoList.size() > 0) {
                    for (StateCheckInfo stateCheckInfo : stateCheckInfoList) {
                        String healthCheck = stateCheckInfo.getHC();
                        JSONArray jsonArray = JSONArray.parseArray(healthCheck);
                        if (jsonArray != null && jsonArray.size() > 0) {
                            for (int i = 0; i < jsonArray.size(); i++) {
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                String checkState = jsonObject.getString("summary");
                                if ("BAD".equals(checkState)) {
                                    badCount++;
                                } else if ("CONCERNING".equals(checkState)) {
                                    concerningCount++;
                                } else {
                                    goodCount++;
                                }
                            }
                            stateCheckInfo.setHC(null);
                            stateCheckInfo.setConc(concerningCount);
                            stateCheckInfo.setBad(badCount);
                            stateCheckInfo.setGood(goodCount);
                        }
                        concerningCount = 0;
                        badCount = 0;
                        goodCount = 0;
                    }
                }
            }

            //处理空白数据
            serviceStateInfos.forEach(main -> {
                List<StateCheckInfo> timeList = new ArrayList<>();
                Map<String, StateCheckInfo> timeMap = new HashMap<>();
                List<StateCheckInfo> stateCountInfoList = main.getStateCountInfoList();
                stateCountInfoList.forEach(stateCheckInfo -> {
                    timeMap.put(stateCheckInfo.getCt(), stateCheckInfo);
                });
                createTimeList.forEach(item -> {
                    String createTime = item.get("CREATE_TIME");
                    StateCheckInfo info = null;
                    if (timeMap.get(createTime) != null) {
                        info = timeMap.get(createTime);
                    } else {
                        info = new StateCheckInfo();
                        info.setCt(createTime);
                        info.setBad(0);
                        info.setConc(0);
                        info.setGood(0);
                    }
                    timeList.add(info);
                    main.setStateCountInfoList(timeList);
                });
            });
        }
        return serviceStateInfos;
    }

    /**
     * 获取一个时间区间的时间集合
     *
     * @return
     */
    public List<Map<String, String>> queryCreateTimeRange(StateBaseReqTimeModel model) {
        //获取日期集合
        List<Map<String, String>> createTimeList;
        if ("".equals(model.getStartTime()) || "".equals(model.getEndTime())) {
            createTimeList = cmStateDao.queryCreateTime();
        } else {
            Map<String, Object> roleMap = new HashMap<>();
            roleMap.put("startTime", model.getStartTime());
            roleMap.put("endTime", model.getEndTime());
            createTimeList = cmStateDao.queryCreateTimeRange(roleMap);
        }
        return createTimeList;
    }

    /**
     * 状态页 查询 角色状态信息
     *
     * @return
     */
    public List<RoleStateInfo> queryRoleState(StateBaseReqTimeModel model) {
        //获取日期集合
        List<Map<String, String>> createTimeList = queryCreateTimeRange(model);
        List<RoleStateInfo> roleStateInfos = cmStateDao.queryRoleState(model);

        //处理空白数据
        roleStateInfos.forEach(roleStateInfo -> {
            List<StateCountInfo> timeList = new ArrayList<>();
            Map<String, StateCountInfo> timeMap = new HashMap<>();
            List<StateCountInfo> stateCountInfoList = roleStateInfo.getStateCountInfoList();
            stateCountInfoList.forEach(stateCheckInfo -> {
                timeMap.put(stateCheckInfo.getCt(), stateCheckInfo);
            });
            createTimeList.forEach(item -> {
                String createTime = item.get("CREATE_TIME");
                StateCountInfo info = null;
                if (timeMap.get(createTime) != null) {
                    info = timeMap.get(createTime);
                } else {
                    info = new StateCountInfo();
                    info.setCt(createTime);
                    info.setBad(0);
                    info.setConc(0);
                    info.setGood(0);
                }
                timeList.add(info);
                roleStateInfo.setStateCountInfoList(timeList);
            });
        });
        return roleStateInfos;
    }

    /**
     * 状态页 查询 健康check信息
     *
     * @return
     */
    public List<RoleStateCheckInfo> queryRoleChecks(StateBaseReqModel model) {
        return cmStateDao.queryRoleChecks(model);
    }

    /**
     * 日常巡检，cm组件异常情况
     *
     * @return
     */
    public Map<String, String> seleveryDayInspect() {
        List<ServiceCountInfo> serviceCountInfos = cmStateDao.seleveryDayInspect();
        Map<String, String> countMap = new HashMap<>();
        for (ServiceCountInfo serviceCountInfo : serviceCountInfos) {
            if (serviceCountInfo.getConc() > 0) {
                String field = serviceCountInfo.getCmName();
                String ss = serviceCountInfo.getType() + "告警、";
                countMap.put(field, countMap.getOrDefault(field, "") + ss);
            }
            if (serviceCountInfo.getBad() > 0) {
                String field = serviceCountInfo.getCmName();
                String ss = "<" + serviceCountInfo.getType() + "异常>、";
                countMap.put(field, countMap.getOrDefault(field, "") + ss);
            }
            if (serviceCountInfo.getConc() == 0 && serviceCountInfo.getBad() == 0) {
                String field = serviceCountInfo.getCmName();
                countMap.put(field, "");
            }
        }
        Map<String, String> strMap = new HashMap<>();
        for (String key : countMap.keySet()) {
            strMap.put(key, countMap.get(key).substring(0, countMap.get(key).length() - 1) + "\n");
        }
        return strMap;
    }

    /**
     * cm组件error情况
     *
     * @return
     */
    public String serviceError() {
        List<ServiceCountInfo> serviceCountInfos = cmStateDao.seleveryDayInspect();
        Map<String, String> countMap = new HashMap<>();
        for (ServiceCountInfo serviceCountInfo : serviceCountInfos) {
            if (serviceCountInfo.getBad() > 0) {
                String field = serviceCountInfo.getCmName();
                String ss = "<" + serviceCountInfo.getType() + "异常>、";
                countMap.put(field, countMap.getOrDefault(field, "") + ss);
            }
        }
        String str = "";
        for (String key : countMap.keySet()) {
            str = str +"【"+ key +"】 "+ countMap.get(key).substring(0, countMap.get(key).length() - 1) + "\n";
        }
        return str;
    }

    public PageResult queryServices(Page page, ServiceState serviceState) {
        if (StrUtil.isBlank(serviceState.getStartTime()) || StrUtil.isBlank(serviceState.getEndTime())){
            return selectPage(cmStateDao, "queryServicesNow", page, serviceState);
        }else {
            return selectPage(cmStateDao, "queryServices", page, serviceState);
        }
    }
}
